#ifndef __TCPSERVER_H__
#define __TCPSERVER_H__

#include "Spark/Net/TcpConnection.h"
#include <string>
#include <set>
#include <map>

class Acceptor;
class EventLoop;
class EventLoopThreadPool;

class TcpServer : public NonCopyable
{
  public:
    TcpServer(EventLoop* loop, const SocketAddr& addr, std::string name);
    ~TcpServer();

    TcpServer() = delete;

    void start();
    void stop();

    void setIoLoopNum(size_t num);

    void setRecvMessageCallback(ConnectionCallbackBuffer_t cb)
    {
        messageCallback_ = std::move(cb);
    }

    void setConnectionCallback(ConnectionCallback_t cb)
    {
        connectionCallback_ = std::move(cb);
    }

    void setWriteCompleteCallback(ConnectionCallback_t cb)
    {
        writeDoneCallback_ = std::move(cb);
    }

    const std::string& name() const
    {
        return serverName_;
    }

    const std::string& ipPort() const
    {
        return ipPort_;
    }

    EventLoop* getLoop() const
    {
        return loop_;
    }

    std::shared_ptr<EventLoopThreadPool> threadPool()
    {
        return threadPool_;
    }

  private:
    using ConnectionMap = std::map<std::string, TcpConnectionPtr>;
    void newConnection(int fd, const SocketAddr& peer);
    void removeConnection(const TcpConnectionPtr& conn);
    void removeConnectionInLoop(const TcpConnectionPtr& conn);
    EventLoop* loop_;
    const std::string ipPort_;
    const std::string serverName_;
    std::unique_ptr<Acceptor> acceptorPtr_;
    std::shared_ptr<EventLoopThreadPool> threadPool_;
    std::set<TcpConnectionPtr> connSet_;
    ConnectionCallbackBuffer_t messageCallback_;
    ConnectionCallback_t connectionCallback_;
    ConnectionCallback_t writeDoneCallback_;
    bool started_{false};
    int nextConnId_{1};
    ConnectionMap connections_;
};

#endif  // __TCPSERVER_H__